1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.util.array; 12 private import hip.util.conv : to; 13 import std.traits : hasElaborateCopyConstructor; 14 version(WebAssembly) version = UseCustomRT; 15 version(PSVita) version = UseCustomRT; 16 17 /** 18 * Uses accessor on the array to find an element 19 */ 20 int indexOf(string accessor, T, Q)(T[] arr, Q element, int startIndex = 0) 21 { 22 static if(accessor != "") 23 enum op = "."~accessor; 24 else 25 enum op = accessor; 26 const size_t len = arr.length; 27 for(size_t i = startIndex; i < len; i++) 28 mixin("if(arr[i]"~op~" == element)return cast(int)i;"); 29 return -1; 30 } 31 /** 32 * Returns index of element if it finds or returns -1 if not 33 */ 34 int indexOf(T)(in T[] arr, T element, int startIndex = 0) pure nothrow @nogc 35 { 36 if(startIndex < 0) 37 return -1; 38 for(int i = startIndex; i < arr.length; i++) 39 if(arr[i] == element) 40 return i; 41 return -1; 42 } 43 import hip.util.reflection; 44 45 ///Index of for tuples 46 int indexOf(T, V)(in T tuple, V value) pure nothrow @nogc if(!isArray!T) 47 { 48 foreach(i, v; tuple) 49 { 50 static if(is(typeof(v) == V)) 51 if(v == value) 52 return i; 53 } 54 return -1; 55 } 56 57 58 59 int lastIndexOf(T)(T[] arr, T element, int startIndex = -1) 60 { 61 const size_t len = arr.length; 62 if(len==0)return-1; 63 if(startIndex < 0) startIndex = (cast(int)len - 1); 64 for(int i = startIndex; i >= 0; i--) 65 if(arr[i] == element) 66 return i; 67 return -1; 68 } 69 70 /** 71 * Should work only for numerics 72 */ 73 int binarySearch(T)(in T[] arr, T element) @nogc @safe nothrow 74 { 75 uint l = 0; 76 uint r = arr.length; 77 uint m; 78 while(l <= r) 79 { 80 m = cast(uint)((l+r)/2); 81 if(arr[m] < element) 82 l = m + 1; 83 else if(arr[m] > element) 84 r = m - 1; 85 else if(arr[m] == element) 86 return m; 87 } 88 89 return -1; 90 } 91 92 bool swapAt(T)(T[] arr, int index1, int index2) @nogc @safe nothrow 93 { 94 if(index1 == index2 || index1 < 0 || index1 >= arr.length || index2 < 0 || index2 >= arr.length) 95 return false; 96 T temp = arr[index1]; 97 arr[index1] = arr[index2]; 98 arr[index2] = temp; 99 return true; 100 } 101 102 /** 103 * Returns if swap was succesful 104 */ 105 bool swapElementsFromArray(T)(T[] arr, T element1, T element2) @nogc @safe nothrow 106 { 107 long index1 = arr.indexOf(element1); 108 long index2 = arr.indexOf(element2); 109 110 if(index1 != -1 && index2 != 1) 111 { 112 T temp = arr[index1]; 113 arr[index1] = arr[index2]; 114 arr[index2] = temp; 115 return true; 116 } 117 return false; 118 } 119 120 121 bool popFront(T)(ref T[] arr, out T val) 122 { 123 import hip.util.memory; 124 if(arr.length == 0) 125 return false; 126 val = arr[0]; 127 memcpy(arr.ptr, arr.ptr+1, (cast(int)arr.length-1)*T.sizeof); 128 arr.length--; 129 return true; 130 } 131 bool popFront(T)(ref T[] arr) 132 { 133 T val; 134 return popFront(arr, val); 135 } 136 bool remove(T)(ref T[] arr, T val) 137 { 138 for(size_t i = 0; i < arr.length; i++) 139 { 140 if(arr[i] == val) 141 { 142 static if(hasElaborateCopyConstructor!T) 143 { 144 for(size_t z = 0; z+i < cast(int)arr.length-1; z++) 145 arr[z+i] = arr[z+i+1]; 146 } 147 else 148 { 149 import core.stdc.string; 150 size_t moveElements = arr.length - i - 1; 151 if(moveElements) 152 memmove(&arr[i], &arr[i+1], moveElements * T.sizeof); 153 } 154 arr.length--; 155 return true; 156 } 157 } 158 return false; 159 } 160 161 bool remove(T)(ref T[] arr, const(T)* val) 162 { 163 for(size_t i = 0; i < arr.length; i++) 164 { 165 if(&arr[i] == val) 166 { 167 static if(hasElaborateCopyConstructor!T) 168 { 169 for(size_t z = 0; z+i < cast(int)arr.length-1; z++) 170 arr[z+i] = arr[z+i+1]; 171 } 172 else 173 { 174 import core.stdc.string; 175 size_t moveElements = arr.length - i - 1; 176 if(moveElements) 177 memmove(&arr[i], &arr[i+1], moveElements * T.sizeof); 178 } 179 arr.length--; 180 return true; 181 } 182 } 183 return false; 184 } 185 186 pragma(inline, true) 187 bool contains(T)(in T[] arr, T val) pure nothrow @nogc {return arr.indexOf(val) != -1;} 188 189 pragma(inline, true) 190 bool contains(T, V)(in T[] tuple, V val) pure nothrow @nogc {return tuple.indexOf(val) != -1;} 191 192 193 /** 194 * Compare a array of structures member with a target value 195 */ 196 bool contains(string accessor, T, Q)(ref T[] arr, Q val) 197 { 198 for(size_t i = 0; i < arr.length; i++) 199 { 200 if(__traits(getMember, arr[i], accessor) == val) 201 return true; 202 } 203 return false; 204 } 205 206 /** 207 * Compare two different structures accessing different members 208 */ 209 bool contains(string accessorA, string accessorB, T, Q)(ref T[] arr, Q val) 210 { 211 for(size_t i = 0; i < arr.length; i++) 212 { 213 if(__traits(getMember, arr[i], accessorA) == __traits(getMember, val, accessorB)) 214 return true; 215 } 216 return false; 217 } 218 219 pragma(inline, true) bool isEmpty(T)(in T[] arr){return arr.length == 0;} 220 221 222 import std.traits:ForeachType; 223 ForeachType!(T)[] array(T)(T range) 224 { 225 typeof(return) ret; 226 foreach(r;range) 227 ret~= r; 228 return ret; 229 } 230 231 string join(T)(T[] arr, string separator = "") 232 { 233 import hip.util.conv; 234 string ret; 235 if(arr.length == 0) return ""; 236 237 ret = toString(arr[0]); 238 for(int i = 1; i < arr.length; i++) 239 { 240 ret~= separator; 241 ret~= arr[i]; 242 } 243 return ret; 244 } 245 246 string join(T)(T[] arr, char separator) 247 { 248 char[1] temp = separator; 249 return join(arr, cast(string)temp); 250 } 251 252 pragma(inline, true) 253 T uninitializedArray(T)(size_t size) 254 { 255 version(UseCustomRT) 256 { 257 return object._d_newarrayU!(typeof(T.init[0]))(size); 258 } 259 else version(D_ProfileGC) 260 { 261 T ret; 262 ret.length = size; 263 return ret; 264 } 265 else 266 { 267 static import std.array; 268 return std.array.uninitializedArray!T(size); 269 } 270 } 271 272 273 void printArrayWithoutValues(T)(const T[] arr, T[] ignoreValues...) 274 { 275 import hip.console.log; 276 string str = "["; 277 MainLoop: foreach (val; arr) 278 { 279 foreach (arg; ignoreValues) 280 if(val == arg) //Ignore if value is in the loop list 281 continue MainLoop; 282 str~= to!string(val) ~", "; 283 } 284 str~= "]"; 285 const int index = lastIndexOf(str, ','); 286 if(index == -1) 287 logln("[]"); 288 else 289 logln(str[0..index] ~ str[index+2..$]); 290 } 291 292 unittest 293 { 294 assert(indexOf([2, 3, 4], 3) == 1); 295 assert(swapElementsFromArray([5, 10, 9], 10, 9)); 296 assert(lastIndexOf([2, 3, 3, 4], 4) == 3); 297 }